package com.uinnova.product.eam.service.asset.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.binary.core.exception.BinaryException;
import com.binary.jdbc.Page;
import com.google.common.collect.Lists;
import com.uinnova.product.eam.base.model.AttrConfInfo;
import com.uinnova.product.eam.base.model.AttrDefInfo;
import com.uinnova.product.eam.base.model.FileResourceMeta;
import com.uinnova.product.eam.base.model.ResourceInfo;
import com.uinnova.product.eam.comm.model.es.EamResource;
import com.uinnova.product.eam.config.Env;
import com.uinnova.product.eam.model.asset.ArchitecturalDTO;
import com.uinnova.product.eam.model.asset.ArchitecturalNameCheckDTO;
import com.uinnova.product.eam.model.asset.ArchitecturalResolutionDTO;
import com.uinnova.product.eam.model.asset.SearchArchitecturalDTO;
import com.uinnova.product.eam.service.asset.ArchitecturalSvc;
import com.uinnova.product.eam.service.es.IamsEamESResourceDao;
import com.uinnova.product.vmdb.comm.model.ci.CCcCiClass;
import com.uinnova.product.vmdb.comm.model.ci.CcCi;
import com.uinnova.product.vmdb.provider.ci.bean.CcCiClassInfo;
import com.uinnova.product.vmdb.provider.ci.bean.CcCiInfo;
import com.uino.bean.cmdb.base.ESCIInfo;
import com.uino.bean.cmdb.query.ESAttrBean;
import com.uino.bean.cmdb.query.ESCIClassSearchBean;
import com.uino.bean.cmdb.query.ESCISearchBean;
import com.uino.api.client.cmdb.ICIApiSvc;
import com.uino.api.client.cmdb.ICIClassApiSvc;
import com.uino.util.rsm.RsmUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class ArchitecturalSvcImpl implements ArchitecturalSvc {


    @Resource
    private ICIApiSvc ciApiSvc;
    @Resource
    private ICIClassApiSvc cIClassApiSvc;
    @Resource
    private IamsEamESResourceDao iamsEamESResourceDao;
    @Autowired
    private RsmUtils rsmUtils;
    @Value("${local.resource.space}")
    private String localPath;

    @Override
    public Long createArchitecturalResolution(ArchitecturalDTO architecturalDTO) {
        List<Long> ids = new ArrayList<>();
        for (ArchitecturalResolutionDTO architecturalResolutionDTO : architecturalDTO.getInfos()) {
            CcCiInfo ciInfo = new CcCiInfo();
            CcCi ci = new CcCi();
            ci.setId(architecturalResolutionDTO.getId());
            ci.setClassId(architecturalResolutionDTO.getClassId());
            if (!CollectionUtils.isEmpty(architecturalResolutionDTO.getAttrs())) {
                architecturalResolutionDTO.getAttrs().put(Env.ARCH_RESOLUTION.getDOC(), JSON.toJSONString(architecturalResolutionDTO.getResources()));
            }
            ciInfo.setAttrs(architecturalResolutionDTO.getAttrs());
            ciInfo.setCi(ci);
            Long id = ciApiSvc.saveOrUpdateCI(ciInfo);
            ids.add(id);
        }

        return ids.get(0);
    }

    public List<Map<String, Object>> getInfoBySubsystemCode(ArchitecturalResolutionDTO architecturalResolutionDTO) {
        ESCISearchBean queryBean = new ESCISearchBean();
        queryBean.setDomainId(1L);
        queryBean.setClassIds(Collections.singletonList(architecturalResolutionDTO.getClassId()));
        ESAttrBean esAttrBean = new ESAttrBean();
        esAttrBean.setKey(Env.ARCH_RESOLUTION.getSubsystemCode());
        esAttrBean.setValue(architecturalResolutionDTO.getSubsystemCode());
        esAttrBean.setOptType(1);
        queryBean.setAndAttrs(Collections.singletonList(esAttrBean));
        queryBean.setSortField("attrs.决议时间");
        queryBean.setAsc(false);
        Page<ESCIInfo> esciInfoPage = ciApiSvc.searchESCIByBean(queryBean);
        List<ESCIInfo> data = esciInfoPage.getData();
        List<Map<String, Object>> result = new ArrayList<>();
        for (ESCIInfo esciInfo : data) {
            Map<String, Object> map = new HashMap<>();
            map.put(Env.ARCH_RESOLUTION.getCiCode(), esciInfo.getCiCode());
            map.put(Env.ARCH_RESOLUTION.getId(), esciInfo.getId());
            map.put(Env.ARCH_RESOLUTION.getResolutionName(), esciInfo.getAttrs().get(Env.ARCH_RESOLUTION.getResolutionName()));
            map.put(Env.ARCH_RESOLUTION.getResolutionTime(), esciInfo.getAttrs().get(Env.ARCH_RESOLUTION.getResolutionTime()));
            map.put(Env.ARCH_RESOLUTION.getReviewMethod(), esciInfo.getAttrs().get(Env.ARCH_RESOLUTION.getReviewMethod()));
            map.put(Env.ARCH_RESOLUTION.getDOC(), JSONObject.parseArray((String) esciInfo.getAttrs().get(Env.ARCH_RESOLUTION.getDOC()), ResourceInfo.class));
            result.add(map);
        }
        return result;
    }

    public ArchitecturalResolutionDTO getInfoByCiId(Long ciId) {
        CcCiInfo ciInfo = ciApiSvc.getCiInfoById(ciId);
        ArchitecturalResolutionDTO architecturalResolutionDTO = new ArchitecturalResolutionDTO();
        architecturalResolutionDTO.setAttrs(ciInfo.getAttrs());
        return architecturalResolutionDTO;
    }

    @Override
    public AttrDefInfo selectAttrConf(AttrConfInfo attrConfInfo) {
        CcCiClassInfo classInfo = findClassInfo(attrConfInfo);
        return findAttrConf(attrConfInfo, classInfo);
    }

    @Override
    public boolean checkArchitecturalName(ArchitecturalNameCheckDTO architecturalNameCheckDTO) {
        if (null != architecturalNameCheckDTO.getCiId() && architecturalNameCheckDTO.getCiId() > 0) {
            CcCiInfo ciInfo = ciApiSvc.getCiInfoById(architecturalNameCheckDTO.getCiId());
            String name = ciInfo.getAttrs().get(Env.ARCH_RESOLUTION.getResolutionName());
            String subsystemCode = ciInfo.getAttrs().get(Env.ARCH_RESOLUTION.getSubsystemCode().toUpperCase());
            if (String.valueOf(name).equals(architecturalNameCheckDTO.getName()) && subsystemCode.equals(architecturalNameCheckDTO.getSubSysCode())) {
                return false;
            }
        }
        CCcCiClass cCcCiClass = new CCcCiClass();
        cCcCiClass.setClassNameEqual(architecturalNameCheckDTO.getArchitecturalClassName());
        List<CcCiClassInfo> ccCiClassInfos = cIClassApiSvc.queryClassByCdt(cCcCiClass);
        ESCISearchBean searchBean = new ESCISearchBean();
        searchBean.setClassIds(Collections.singletonList(ccCiClassInfos.get(0).getCiClass().getId()));
        ArrayList<ESAttrBean> objects = Lists.newArrayList();
        ESAttrBean attrBean = new ESAttrBean();
        attrBean.setOptType(1);
        attrBean.setValue(architecturalNameCheckDTO.getName());
        attrBean.setKey(Env.ARCH_RESOLUTION.getResolutionName());
        objects.add(attrBean);
        ESAttrBean subAttrBean = new ESAttrBean();
        subAttrBean.setOptType(1);
        subAttrBean.setValue(architecturalNameCheckDTO.getSubSysCode());
        subAttrBean.setKey(Env.ARCH_RESOLUTION.getSubsystemCode());
        objects.add(subAttrBean);
        searchBean.setAndAttrs(objects);
        Page<ESCIInfo> page = ciApiSvc.searchESCIByBean(searchBean);
        return page.getTotalRows() > 0;
    }

    @Override
    public ESCIInfo searchArchitecturalDTO(SearchArchitecturalDTO searchArchitecturalDTO) {
        CCcCiClass cCcCiClass = new CCcCiClass();
        cCcCiClass.setClassNameEqual(searchArchitecturalDTO.getArchitecturalClassName());
        List<CcCiClassInfo> ccCiClassInfos = cIClassApiSvc.queryClassByCdt(cCcCiClass);
        Map<String, CcCiClassInfo> classMap = ccCiClassInfos.stream()
                .collect(Collectors.toMap(key -> key.getCiClass().getClassName(), value -> value, (key1, key2) -> key2));
        ESCISearchBean queryBean = new ESCISearchBean();
        queryBean.setDomainId(Env.ARCH_RESOLUTION.getDomainId());
        queryBean.setIds(Collections.singletonList(searchArchitecturalDTO.getId()));
        queryBean.setClassIds(Collections.singletonList(classMap.get(searchArchitecturalDTO.getArchitecturalClassName()).getCiClass().getId()));
        Page<ESCIInfo> esciInfoPage = ciApiSvc.searchESCIByBean(queryBean);
        List<ESCIInfo> data = esciInfoPage.getData();
        return data.get(0);
    }

    @Override
    public List<Long> getResIdsById(Long architecturalId) {
        CcCiInfo ciInfo = ciApiSvc.getCiInfoById(architecturalId);
        List<ResourceInfo> resourceInfos = JSONObject.parseArray(ciInfo.getAttrs().get(Env.ARCH_RESOLUTION.getDOC()), ResourceInfo.class);
        return resourceInfos.stream().map(ResourceInfo::getId).collect(Collectors.toList());
    }

    @Override
    public List<FileResourceMeta> download(List<Long> resIds) {
        List<FileResourceMeta> resources = new ArrayList<>(resIds.size());
        resIds.forEach(id -> {
            EamResource resource = iamsEamESResourceDao.getById(id);
            resources.add(new FileResourceMeta(resource, localPath));
            rsmUtils.downloadRsmAndUpdateLocalRsm(resource.getResPath());
        });
        return resources;
    }

    @Override
    public List<Long> changeSubsystemCode(String sourceCode, String targetCode, Long ciClassIdByName) throws BinaryException {
        List<Long> ids = new ArrayList<>();
        ESCISearchBean queryBean = new ESCISearchBean();
        queryBean.setDomainId(1L);
        queryBean.setClassIds(Collections.singletonList(ciClassIdByName));
        ESAttrBean esAttrBean = new ESAttrBean();
        esAttrBean.setKey(Env.ARCH_RESOLUTION.getSubsystemCode());
        esAttrBean.setValue(sourceCode);
        esAttrBean.setOptType(1);
        queryBean.setAndAttrs(Collections.singletonList(esAttrBean));
        Page<ESCIInfo> esciInfoPage = ciApiSvc.searchESCIByBean(queryBean);
        List<ESCIInfo> data = esciInfoPage.getData();
        if(data == null){
            throw new BinaryException("要变更的架构决议不存在");
        }
        data.forEach(each -> each.getAttrs().put(Env.ARCH_RESOLUTION.getSubsystemCode().toUpperCase(),targetCode));
        List<CcCiInfo> ccCiInfos = coverToCiInfo(data);
        for (CcCiInfo ccCiInfo : ccCiInfos) {
            ids.add(ciApiSvc.saveOrUpdateCI(ccCiInfo));
        }
        return ids;
    }

    private AttrDefInfo findAttrConf(AttrConfInfo attrConfInfo, CcCiClassInfo classInfo) {
        AttrDefInfo data = new AttrDefInfo();
        data.setAttrDefs(classInfo.getAttrDefs());
        data.setClassCode(classInfo.getCiClass().getClassCode());
        data.setClassId(classInfo.getCiClass().getId());
        data.setHiddenAttrs(attrConfInfo.getHiddenAttrs());
        data.setSelectableAttrs(attrConfInfo.getSelectableAttrs());
        return data;
    }

    private CcCiClassInfo findClassInfo(AttrConfInfo attrConfInfo) {
        ESCIClassSearchBean searchBean = new ESCIClassSearchBean();
        CCcCiClass cdt = new CCcCiClass();
        cdt.setClassCode(attrConfInfo.getClassCode());
        cdt.setDataStatus(1);
        searchBean.setCdt(cdt);
        List<CcCiClassInfo> ccCiClassInfos = cIClassApiSvc.queryCiClassInfoListBySearchBean(searchBean);
        return ccCiClassInfos.get(0);
    }

    private List<CcCiInfo> coverToCiInfo(List<ESCIInfo> list){
        List<CcCiInfo> coverList = new ArrayList<>();
        for(ESCIInfo esciInfo : list){
            CcCiInfo ccCiInfo = new CcCiInfo();
            CcCi ci = new CcCi();
            ci.setId(esciInfo.getId());
            ci.setClassId(esciInfo.getClassId());
            ccCiInfo.setCi(ci);
            Map<String,String> map = new HashMap<>();
            Map<String, Object> attrs = esciInfo.getAttrs();
            attrs.forEach((k,v)->map.put(k,v!=null?v.toString():null));
            ccCiInfo.setAttrs(map);
            coverList.add(ccCiInfo);
        }
        return coverList;
    }

}
